﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.IO;

using Might.ServiceServer.SvnAccess;

namespace Might.ServiceServer.SvnService {

    public class SvnService : ISvnService {

        /// <summary>
        /// Server Directory, where temporary files are stored
        /// </summary>
        private string TEMP_DIR = "C:\\Temp\\";

        /// <summary>
        /// Returns list of files in repository. (svn list)
        /// </summary>
        /// <param name="address">Repository address.</param>
        /// <param name="username">Username to svn repository.</param>
        /// <param name="password">Password to svn repository.</param>
        /// <returns>List of files and directories in string form.</returns>
        public List<string> Svn_List(string address, string username, string password) {
            return Svn.List(address, username, password);
        }

        /// <summary>
        /// Save changes from your working copy on server side to the repository.
        /// </summary>
        /// <param name="from_where">Addrees from where will be changes saved.</param>
        /// <returns>True if commit is successfully completed, False otherwise.</returns>
        public bool Svn_Commit(string from_where) {
            return Svn.Commit(from_where);
        }

        /// <summary>
        /// Performs a recursive checkout from address_from to address_where on server.
        /// </summary>
        /// <param name="svn_address">Repository address.</param>
        /// <param name="username">Username to svn repository.</param>
        /// <param name="password">Password to svn repository.</param>
        /// <returns>True if checkout is successfully completed, False otherwise.</returns>
        public bool Svn_Checkout(string svn_address, string username, string password) {
            String TempUserDirectory = TEMP_DIR + username + "\\";
            if (!Directory.Exists(TempUserDirectory)) {
                Directory.CreateDirectory(TempUserDirectory);
            }
            return Svn.Checkout(svn_address, TempUserDirectory, username, password);
        }

        /// <summary>
        /// Returns content od file.
        /// </summary>
        /// <param name="svn_file_address">File address in svn repository.</param>
        /// <param name="username">Username to svn repository.</param>
        /// <param name="password">Password to svn repository.</param>
        /// <returns>File content, or ERROR message.</returns>
        public string Svn_LoadFile(string svn_file_address, string username, string password) {

            String SvnDirectoryPathToFile = svn_file_address.Substring(0, svn_file_address.LastIndexOf('/'));
            String TempUserDirectory = TEMP_DIR + username + "\\";

            Directory.CreateDirectory(TempUserDirectory);

            String TempLoadFileName = TEMP_DIR + svn_file_address.Substring(svn_file_address.LastIndexOf('/') + 1);
            String LoadFileText = "ERROR";

            try {
                Svn.Checkout(SvnDirectoryPathToFile, TempUserDirectory, username, password);
            }
            catch {
                LoadFileText = "ERROR: SVN CONNECT";
                goto CleanUp;
            }

            FileStream LoadFile;
            try {
                LoadFile = new FileStream(@TempLoadFileName, FileMode.Open);
            }
            catch {
                LoadFileText = "ERROR: FILE CANNOT BE FIND";
                goto CleanUp;
            }
            StreamReader Reader = new StreamReader(LoadFile);
            LoadFileText = Reader.ReadToEnd();
            Reader.Close();
            LoadFile.Close();

CleanUp:
            DeleteDirectory(TempUserDirectory);

            return LoadFileText;
        }

        /// <summary>
        /// Save new content of file (under subversion) to the repository.
        /// </summary>
        /// <param name="svn_file_address">File address in svn repository.</param>
        /// <param name="username">Username to svn repository.</param>
        /// <param name="password">Password to svn repository.</param>
        /// <param name="filetext">New content of selected file.</param>
        /// <returns>True if Svn_SaveFile is successfully completed, False otherwise.</returns>
        public bool Svn_SaveFile(string svn_file_address, string username, string password, string filetext) {

            String SvnDirectoryPathToFile = svn_file_address.Substring(0, svn_file_address.LastIndexOf('/'));
            String TempUserDirectory = TEMP_DIR + username + "\\";

            Directory.CreateDirectory(TempUserDirectory);

            String TempSaveFileName = TEMP_DIR + svn_file_address.Substring(svn_file_address.LastIndexOf('/') + 1);
            Boolean Result = true;

            try {
                Svn.Checkout(SvnDirectoryPathToFile, TempUserDirectory, username, password);
            }
            catch {
                Result = false;
                goto CleanUp;
            }

            FileStream SaveFile;
            try {
                SaveFile = new FileStream(@TempSaveFileName, FileMode.Truncate, FileAccess.Write);
            }
            catch {
                Result = false;
                goto CleanUp;
            }
            StreamWriter Writer = new StreamWriter(SaveFile);
            Writer.Write(filetext);
            Writer.Flush();
            Writer.Close();
            SaveFile.Close();

            try {
                Svn.Commit(TempUserDirectory);
            }
            catch {
                Result = false;
            }

CleanUp:
            DeleteDirectory(TempUserDirectory);

            return Result;
        }

        /// <summary>
        /// Function deleted recursively a directory.
        /// </summary>
        /// <param name="target_dir">Directory that will be deleted.</param>
        private void DeleteDirectory(string target_dir) {
            string[] files = Directory.GetFiles(target_dir);
            string[] dirs = Directory.GetDirectories(target_dir);

            foreach (string file in files) {
                File.SetAttributes(file, FileAttributes.Normal);
                File.Delete(file);
            }

            foreach (string dir in dirs) {
                DeleteDirectory(dir);
            }

            Directory.Delete(target_dir, false);
        }

        /// <summary>
        /// Clean all temporary files of selected Might user.
        /// </summary>
        /// <param name="mightUsername">Might username to be cleaned.</param>
        /// <returns>True if clean is successfully completed, False otherwise.</returns>
        public bool Clean(string mightUsername){
            bool Result = false;
            String TempUserDirectory = TEMP_DIR + mightUsername + "\\";

            try {
                DeleteDirectory(TempUserDirectory);
            }
            catch {
                Result = false;
            }

            return Result;
        }

        /// <summary>
        /// Function returned a stream handle to specific file.
        /// </summary>
        /// <param name="svnAddress">File address in svn repository.</param>
        /// <param name="svnUsername">Username to svn repository.</param>
        /// <param name="svnPassword">Password to svn repository.</param>
        /// <param name="mightUsername">File owner - Might username.</param>
        /// <param name="fileMode">FileMode property.</param>
        /// <param name="fileAccess">FileAccess property.</param>
        /// <returns>File stream of specific file.</returns>
        public Stream GetFile(string svnAddress, string svnUsername, string svnPassword, string mightUsername, FileMode fileMode, FileAccess fileAccess) {

            string address = "";
            string file = svnAddress.Substring(svnAddress.LastIndexOf('/')+1);  // filename
            svnAddress = svnAddress.Remove(svnAddress.LastIndexOf('/'));        // svn address to directory where file is

            if (svnAddress.StartsWith("http://")){
                address = svnAddress.Substring(7);
            }
            else if (svnAddress.StartsWith("svn://")) {
                address = svnAddress.Substring(6);
            }
            else if (svnAddress.StartsWith("file:///")) {
                address = svnAddress.Substring(8);
            }

            String FilePath = TEMP_DIR + mightUsername + "\\";

            char[] delimiterChars = { '/' };
            string[] pathFragments = address.Split(delimiterChars);
            
            foreach (string path in pathFragments){     // Path to file in server
                FilePath += path + "\\";
            }

            Svn.Checkout(svnAddress, FilePath, svnUsername, svnPassword);   // checkout file to server

            FilePath += file;           // Absolute path to the file stored on server

            try {
                FileStream GettingFile = File.Open(FilePath, fileMode, fileAccess);
                return GettingFile;
            }
            catch (IOException ex) {
                // Exception returned -> File is not accessible
                throw ex;
            }

        }

        /// <summary>
        /// Create a new file and add it to the repository.
        /// </summary>
        /// <param name="address">Local File address (from File Browser).</param>
        /// <param name="username">Username to svn repository.</param>
        /// <param name="password">Password to svn repository.</param>
        /// <returns>File stream of new file.</returns>
        public Stream NewFileUnderRepository(string address, string username, string password) {

            // Before this must be done Checkout for this user !!!!

            String FilePath = TEMP_DIR + username + "\\" + address;
            FileStream GettingFile;

            try {
                GettingFile = new FileStream(@FilePath, FileMode.Create);
                Svn.Add(FilePath, username, password);  // File addes to repository
            }
            catch (IOException ex) {
                // Exception returned -> File is not accessible
                throw ex;
            }

            return GettingFile;
        }

    }
}
